<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="description" content="">
    <meta name="author" content="">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>lasmap</title>

	<link rel="stylesheet" href="http://openlayers.org/en/v3.11.2/css/ol.css" type="text/css">
  </head>

  <body>
  
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.12/proj4.js"></script>
	<script src="http://openlayers.org/en/v3.11.2/build/ol.js"></script>


	<div id="potree_map" style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%">
		<div id="potree_map_content" class="map" style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%"></div>
	</div>
		
	
	<script>
	
	var gExtent = null;
	var sourcesLayer = null;
	var sourcesLabelLayer = null;
	var dragBoxLayer = null;
	var sceneProjection = null;
	var map = null;
	var olCenter = null;
	var mapProjectionName = "EPSG:3857";
	var mapProjection = proj4.defs(mapProjectionName);
	
	var toMap = null;
	var toScene = null;
	
	// from http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
	function getParameterByName(name) {
		name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
		var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
			results = regex.exec(location.search);
		return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
	}
	
	var source = getParameterByName("sources");
	
	<!-- INCLUDE SOURCE -->
	
	var sourceurl = source.substring(0, source.lastIndexOf("/") + 1) + "sources";
	
	function init(){
		gExtent = new ol.geom.LineString([[0,0], [0,0]]);
		
		// EXTENT LAYER
		var feature = new ol.Feature(gExtent);
		var featureVector = new ol.source.Vector({
			features: [feature]
		});
		var visibleBoundsLayer = new ol.layer.Vector({
			source: featureVector,
			style: new ol.style.Style({
				fill: new ol.style.Fill({
					color: 'rgba(255, 255, 255, 0.2)'
				}),
				stroke: new ol.style.Stroke({
					  color: '#0000ff',
					  width: 2
				}),
				image: new ol.style.Circle({
					radius: 3,
					fill: new ol.style.Fill({
						color: '#0000ff'
					})
				})
			})
		});
		
		// SOURCES EXTENT LAYER
		sourcesLayer = new ol.layer.Vector({
			source: new ol.source.Vector({}),
			style: new ol.style.Style({
				fill: new ol.style.Fill({
					color: 'rgba(0, 0, 150, 0.1)'
				}),
				stroke: new ol.style.Stroke({
					  color: 'rgba(0, 0, 150, 1)',
					  width: 1
				})
			})
		});
		
		// SOURCES LABEL LAYER
		sourcesLabelLayer = new ol.layer.Vector({
			source: new ol.source.Vector({
			}),
			style: new ol.style.Style({
				fill: new ol.style.Fill({
					color: 'rgba(255, 0, 0, 0.1)'
				}),
				stroke: new ol.style.Stroke({
					  color: 'rgba(255, 0, 0, 1)',
					  width: 2
				})
			}),
			minResolution: 0.01,
            maxResolution: 20
		});
		
		var mousePositionControl = new ol.control.MousePosition({
			coordinateFormat: ol.coordinate.createStringXY(4),
			projection: sceneProjection,
			undefinedHTML: '&nbsp;'
		});
		
		var DownloadSelectionControl = function(opt_options) {
			var options = opt_options || {};
			
			// TOGGLE TILES
			var btToggleTiles = document.createElement('button');
			btToggleTiles.innerHTML = 'T';
			btToggleTiles.addEventListener('click', function(){
				var visible = sourcesLayer.getVisible();
				sourcesLayer.setVisible(!visible);
				sourcesLabelLayer.setVisible(!visible);
			}, false);
			btToggleTiles.style.float = "left";
			btToggleTiles.title = "show / hide tiles";
			
			
			
			// DOWNLOAD SELECTED TILES
			var link = document.createElement("a");
			link.href = "#";
			link.download = "list.txt";
			link.style.float = "left";
			
			var button = document.createElement('button');
			button.innerHTML = 'D';
			link.appendChild(button);
			
			var this_ = this;
			var handleDownload = function(e) {
				var features = selectedFeatures.getArray();
				
				var url =  [location.protocol, '//', location.host, location.pathname].join('');
				
				if(features.length === 0){
					alert("No tiles were selected. Select area with ctrl + left mouse button!");
					e.preventDefault();
					e.stopImmediatePropagation();
					return false;
				}else if(features.length === 1){
					var feature = features[0];
					
					if(feature.source){
						var sourceurl = new URL(document.location.href + "/../" + source + '/../source/' + feature.source.name);
						link.href = sourceurl.href;
						link.download = feature.source.name;
					}
				}else{
					var content = "";
					for(var i = 0; i < features.length; i++){
						var feature = features[i];
						
						if(feature.source){
							var sourceurl = new URL(document.location.href + "/../" + source + '/../source/' + feature.source.name);
							content += sourceurl.href + "\n";
						}
					}
					
					var uri = "data:application/octet-stream;base64,"+btoa(content);
					link.href = uri;
					link.download = "list_of_files.txt";
				}
			};
			
			button.addEventListener('click', handleDownload, false);
			
			// assemble container
			var element = document.createElement('div');
			element.className = 'ol-unselectable ol-control';
			element.appendChild(link);
			element.appendChild(btToggleTiles);
			element.style.bottom = "0.5em";
			element.style.left = "0.5em";
			element.title = "Download file or list of selected tiles. Select tile with left mouse button or area using ctrl + left mouse.";
			
			ol.control.Control.call(this, {
				element: element,
				target: options.target
			});
			
		};
		ol.inherits(DownloadSelectionControl, ol.control.Control);
		
		map = new ol.Map({
			controls: ol.control.defaults({
				attributionOptions: ({
				collapsible: false
				})
			}).extend([
				new DownloadSelectionControl(),
				mousePositionControl
			]),
			layers: [
				new ol.layer.Tile({source: new ol.source.OSM()}),
				sourcesLayer,
				sourcesLabelLayer,
				visibleBoundsLayer,
			],
			target: 'potree_map_content',
			view: new ol.View({
				center: olCenter,
				zoom: 9
			})
		});

		// DRAGBOX / SELECTION
		dragBoxLayer = new ol.layer.Vector({
			source: new ol.source.Vector({}),
			style: new ol.style.Style({
				stroke: new ol.style.Stroke({
					  color: 'rgba(0, 0, 255, 1)',
					  width: 2
				})
			})
		});
		map.addLayer(dragBoxLayer);
		
		var select = new ol.interaction.Select();
		map.addInteraction(select);
		
		var selectedFeatures = select.getFeatures();
        
		var dragBox = new ol.interaction.DragBox({
		  condition: ol.events.condition.platformModifierKeyOnly
		});
        
		map.addInteraction(dragBox);
        
		
		dragBox.on('boxend', function(e) {
		  // features that intersect the box are added to the collection of
		  // selected features, and their names are displayed in the "info"
		  // div
		  var extent = dragBox.getGeometry().getExtent();
		  sourcesLayer.getSource().forEachFeatureIntersectingExtent(extent, function(feature) {
			selectedFeatures.push(feature);
		  });
		});
		
		// clear selection when drawing a new box and when clicking on the map
		dragBox.on('boxstart', function(e) {
		  selectedFeatures.clear();
		});
		map.on('click', function() {
		  selectedFeatures.clear();
		});
	};
	
	function setSceneProjection(proj){
		sceneProjection = proj;
		toMap = proj4(sceneProjection, mapProjection);
		toScene = proj4(mapProjection, sceneProjection);
	};
	
	function load(url){
		var createLabelStyle = function(text){
			var style = new ol.style.Style({
				image: new ol.style.Circle({
					fill: new ol.style.Fill({
						color: 'rgba(100,50,200,0.5)'
					}),
					stroke: new ol.style.Stroke({
						color: 'rgba(120,30,100,0.8)',
						width: 3
					})
				}),
				text: new ol.style.Text({
					font: '12px helvetica,sans-serif',
					text: text,
					fill: new ol.style.Fill({
						color: '#000'
					}),
					stroke: new ol.style.Stroke({
						color: '#fff',
						width: 2
					})
				})
			});
			
			return style;
		}
	
		$.getJSON(url, function(data){
			var sources = data.sources;
			
			setSceneProjection(data.projection);
			
			var extent = {
				min: [Infinity, Infinity],
				max: [-Infinity, -Infinity]
			};
			
			for(var i = 0; i < sources.length; i++){
				var source = sources[i];
				var name = source.name;
				var points = source.points;
				var bounds = source.bounds;
				
				extent.min[0] = Math.min(extent.min[0], bounds.min[0]);
				extent.min[1] = Math.min(extent.min[1], bounds.min[1]);
				extent.max[0] = Math.max(extent.max[0], bounds.max[0]);
				extent.max[1] = Math.max(extent.max[1], bounds.max[1]);

				var mapBounds = {
					min: toMap.forward( [bounds.min[0], bounds.min[1]] ),
					max: toMap.forward( [bounds.max[0], bounds.max[1]] )
				}
				var mapCenter = [
					(mapBounds.min[0] + mapBounds.max[0]) / 2,
					(mapBounds.min[1] + mapBounds.max[1]) / 2,
				];
				
				var p1 = toMap.forward( [bounds.min[0], bounds.min[1]] );
				var p2 = toMap.forward( [bounds.max[0], bounds.min[1]] );
				var p3 = toMap.forward( [bounds.max[0], bounds.max[1]] );
				var p4 = toMap.forward( [bounds.min[0], bounds.max[1]] );
				
				var boxes = [];
				//var feature = new ol.Feature({
				//	'geometry': new ol.geom.LineString([p1, p2, p3, p4, p1])
				//});
				var feature = new ol.Feature({
					'geometry': new ol.geom.Polygon([[p1, p2, p3, p4, p1]])
				});
				feature.source = source;
				sourcesLayer.getSource().addFeature(feature);
				
                
				feature = new ol.Feature({
					 geometry: new ol.geom.Point(mapCenter),
					 name: name 
				});
				feature.setStyle(createLabelStyle(name));
				sourcesLabelLayer.getSource().addFeature(feature);
			}
			
			sceneExtent = extent;
			
			
			
			var mapExtent = getMapExtent();
			var mapCenter = getMapCenter();
			
			var view = map.getView();
			view.setCenter(mapCenter);
			
			gExtent.setCoordinates([
				mapExtent.bottomLeft, 
				mapExtent.bottomRight, 
				mapExtent.topRight, 
				mapExtent.topLeft,
				mapExtent.bottomLeft
			]);
			
			view.fit(gExtent, [300, 300], {
				constrainResolution: false
			});
			
		});
	};
	
	function getMapExtent(){
		var e = sceneExtent;
	
		var bottomLeft = toMap.forward([e.min[0], e.min[1]]);
		var bottomRight = toMap.forward([e.max[0], e.min[1]]);
		var topRight = toMap.forward([e.max[0], e.max[1]]);
		var topLeft = toMap.forward([e.min[0], e.max[1]]);
		
		var mapExtent = {
			bottomLeft: bottomLeft,
			bottomRight: bottomRight,
			topRight: topRight,
			topLeft: topLeft
		};
		
		return mapExtent;
	};
	
	this.getMapCenter = function(){
		var mapExtent = getMapExtent();
		
		var mapCenter = [
			(mapExtent.bottomLeft[0] + mapExtent.topRight[0]) / 2, 
			(mapExtent.bottomLeft[1] + mapExtent.topRight[1]) / 2
		];
		
		return mapCenter;
	};	
	
	function update(){
		requestAnimationFrame(update);
	};


	init();
	load(source);
	update();
	
	</script>
  </body>
</html>
